在 Day21 - 物件的基礎概念2 中有提到函式是物件的一個子型別,所以它本身就是一個物件,但函式又與一般的物件有些需不同,詳述如下:
函式通常會包括以下內容:
小括號 ()
,而小括號內可以有以 逗號 ,
分開的多個參數大括號 {}
,大括號內為程式碼片段以下為簡單的函式範例:
透過 關鍵字 function
來宣告一個函式,而 fun
是這個函式的名子,小括號 ()
內為此函式的參數,而在 大括號 {}
內寫入程式碼片段,並可在內使用 return
使函式回傳值,最後可以利用 fun('參數');
,呼叫此函式,也因 fun('參數');
是表達式,可以回傳值,因此也可以賦予到變數上
function fun(parameter1, parameter2) {
var local = '區域變數'
console.log(local)
return parameter1 + parameter2;
}
var call = fun('參數1', '參數2');
console.log(call);
而函式與一般物件的不同在於:
函式可以被分為函式陳述式與函式表達式
函式陳述式又稱 具名函式
,意思就是有名子的函式,可以直接利用名子呼叫函式
函式是否需要名稱,在於函式是否能夠被調用,可被調用就可省略
(ex: 當賦予到變數上,可直接使用變數呼叫,此函式就不需要定義名稱)
function fun() {
console.log(fun);
}
fun(); // 呼叫函式陳述式
/*
ƒ fun() {
console.log(fun);
}
*/
不能使用函式陳述式的例子:
- 立即函式
- 物件內的方法
函式表達式,是先宣告一個變數,透過 = 運算子
將 function
宣告的函式,賦予到此變數上,而此函式不一定需要名稱,若 沒有定義函式名稱則為 匿名函式
因將函式賦予到
變數 fun
上,變數 fun
接收的是此函式的參考路徑
var fun = function () {
console.log(fun);
}
fun(); // 呼叫函式表達式
/*
ƒ fun() {
console.log(fun);
}
*/
當具名函式賦予到變數上,也是函式表達式,但需要注意的是在此狀況下,此具名函式只能在函式內被調用,如果在函式外調用則會出錯
var fun = function fun2() {
console.log(fun);
console.log(fun2);
}
fun();
/*
ƒ fun2() {
console.log(fun);
console.log(fun2);
}
ƒ fun2() {
console.log(fun);
console.log(fun2);
}
*/
fun2(); // 因在函式外調用,故出現錯誤訊息
// Uncaught ReferenceError: fun2 is not defined
在 Day7 - 提升 章節有提到關於函式的提升,在此複習一下:
函式陳述式
會在創造階段時,先在記憶體中將函式陳述式的所有內容做保留
function fn() {
// ...
}
fn();
運作過程:
// 1.創造階段
function fn() {
// ...
}
// 1.執行階段
fn();
函式表達式
創造階段時只會將它的變數先在記憶體中保留空間,直到執行階段才會將函式賦予給此變數,所以若要利用函式表達式,就必須等函式已經賦予到變數上,才能運行此函式
var fn = function () {
// ...
}
fn();
運作過程:
// 1.創造階段
var fn;
// 1.執行階段
fn = function () {
// ...
}
fn();
在 Airbnb 的規範中,會建議盡量避免使用陳述式,使用為具名函式的函式表達式,這是為了在大型專案中,函式陳述式的提升性質可能會影響其他程式碼運行,而使用具名函式的函式表達式而非用匿名函式,則是因具名函式因具有名子能更方便除錯,以下範例取自 Airbnb 規範:
// bad
function foo() {
// ...
}
// bad
const foo = function () {
// ...
};
// good
// lexical name distinguished from the variable-referenced invocation(s)
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};